/**
 * 日期时间处理类
 * 
 * @author 钟伟雄
 * 
 */

package com.ykzb.util;

import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import com.ykzb.base.constants.Constant;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class YkzbDateTimeUtil implements Constant
{
	public final static long millisecondsPerMinute = 60L * 1000L;
	public final static long millisecondsPerHour = 60L * millisecondsPerMinute;
	public final static long millisecondsPerDay = 24L * millisecondsPerHour;
	public final static long millisecondsPerWeek = 7L * millisecondsPerDay;

	public static String dateFormat(Timestamp d)
	{
		return d == null ? null : new SimpleDateFormat(SDFyyyyMMdd).format(d);
	}

	public static String DateTimeFormat(Date d)
	{
		return d == null ? null : new SimpleDateFormat(SDFyyyyMMddHHmmss).format(d);
	}

	public static Timestamp toTimestamp(Date d)
	{
		return (d == null) ? null : new Timestamp(d.getTime());
	}

	public static Timestamp toTimestamp(String str)
	{
		if (TopUtil.isValidValue(str))
		{
			int len = str.length();
			if (len < 29)
			{
				for (int i = 0; i < 29 - len; i++)
				{
					str = str + "0";
				}
			}
			return Timestamp.valueOf(str);
		}
		return null;
	}

	/**
	 * Function to shift the original date the number of days specified by the numDays parameter
	 * 
	 * @param oldDate
	 *            Date
	 * @param numDays
	 *            int
	 * @return Date
	 */
	public static Date dateAdd(Date oldDate, int numDays)
	{
		if (TopUtil.isValidValue(oldDate))
		{
			Date newDate = new Date();
			newDate.setTime(oldDate.getTime() + numDays * millisecondsPerDay);
			return newDate;
		}
		return null;
	}

	/**
	 * Function to shift the original date the number of months specified by the numMonths parameter
	 * 
	 * @param oldDate
	 *            Date
	 * @param numMonths
	 *            int
	 * @return Date
	 */
	public static Date dateAddMonths(Date oldDate, int numMonths)
	{
		if (oldDate == null || numMonths == 0)
		{
			return oldDate;
		}
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTime(oldDate);
		calendar.setLenient(true);
		calendar.add(Calendar.MONTH, numMonths);
		return calendar.getTime();
	}

	/**
	 * Function to shift the original date the number of weeks specified by the numWeeks parameter
	 * 
	 * @param oldDate
	 *            java.util.Date
	 * @param numWeeks
	 *            int
	 * @return Date
	 */
	public static Date dateAddWeeks(Date oldDate, int numWeeks)
	{
		if (TopUtil.isValidValue(oldDate))
		{
			return new Date(oldDate.getTime() + numWeeks * millisecondsPerWeek);
		}
		return null;
	}

	/**
	 * 在oldDate时间基础上，对oldDate时间进行相加或者相减numHours个小时。
	 * 
	 * @param oldDate
	 * @param numHours
	 * @return
	 */
	public static Date dateAddHours(Date oldDate, int numHours)
	{
		if (TopUtil.isValidValue(oldDate))
		{
			return new Date(oldDate.getTime() + numHours * millisecondsPerHour);
		}
		return null;
	}

	/**
	 * 在oldDate时间基础上，对oldDate时间进行相加或者相减numMinus个分时钟。
	 * 
	 * @param oldDate
	 * @param numMinus
	 * @return
	 */
	public static Date dateAddMinus(Date oldDate, int numMinus)
	{
		if (TopUtil.isValidValue(oldDate))
		{
			return new Date(oldDate.getTime() + numMinus * millisecondsPerMinute);
		}
		return null;
	}

	/**
	 * Function to return the number of days between two java.util.Date's The first date is
	 * subtracted from the second date.
	 * 
	 * @param first
	 *            Date
	 * @param second
	 *            Date
	 * @return int
	 */
	public static int dateDiff(Date first, Date second)
	{
		if (first == null || second == null)
		{
			return 0;
		}
		long timeDiff = second.getTime() - first.getTime();
		long approxDays = timeDiff / millisecondsPerDay;
		if (timeDiff > 0 && timeDiff < millisecondsPerDay)
		{
			approxDays = 1;
		}
		if (timeDiff % millisecondsPerDay != 0)
		{
			if (approxDays <= 0 && (timeDiff - millisecondsPerHour) == ((approxDays - 1) * millisecondsPerDay))
			{
				approxDays--;
			} else if (approxDays >= 0 && (timeDiff + millisecondsPerHour) == ((approxDays + 1) * millisecondsPerDay))
			{
				approxDays++;
			}
		}
		return (int) approxDays;
	}

	/**
	 * Function to return the number of full months between two java.util.Date objects. If the first
	 * date occurs after the second date, zero is returned.
	 * 
	 * @param first
	 *            Date
	 * @param second
	 *            Date
	 * @return int
	 */
	public static int dateDiffMonths(Date first, Date second)
	{
		if (first == null || second == null || first.equals(second))
		{
			return 0;
		}
		GregorianCalendar firstCalendar = new GregorianCalendar();
		firstCalendar.setTime(first);
		int firstDay = firstCalendar.get(Calendar.DAY_OF_MONTH);
		int firstMonth = firstCalendar.get(Calendar.MONTH);
		int firstYear = firstCalendar.get(Calendar.YEAR);

		GregorianCalendar secondCalendar = new GregorianCalendar();
		secondCalendar.setTime(second);
		int secondDay = secondCalendar.get(Calendar.DAY_OF_MONTH);
		int secondMonth = secondCalendar.get(Calendar.MONTH);
		int secondYear = secondCalendar.get(Calendar.YEAR);

		int monthDiff = 0;

		if (firstCalendar.before(secondCalendar))
		{
			if (firstYear == secondYear && firstMonth < secondMonth)
			{
				monthDiff += secondMonth - firstMonth;
				if (firstDay > secondDay)
				{
					monthDiff--;
				}
			} else if (firstYear != secondYear)
			{
				monthDiff += (secondYear - firstYear - 1) * 12;
				monthDiff += Calendar.DECEMBER - firstMonth;
				monthDiff += secondMonth - Calendar.JANUARY;
				if (firstDay <= secondDay)
				{
					monthDiff++;
				}
			}
		} else
		{
			Log log = LogFactory.getLog(YkzbDateTimeUtil.class.getName());
			log.error("First must before Second.");
		}
		return monthDiff;
	}

	/**
	 * Function to return the number of weeks between two java.util.Date's
	 * 
	 * @param first
	 *            Date
	 * @param second
	 *            Date
	 * @return int
	 */
	public static int dateDiffWeeks(Date first, Date second)
	{
		return dateDiff(first, second) / 7;
	}

	public static String getDateString(Date javaDate, String dateFormat)
	{
		if (javaDate == null)
		{
			return null;
		} else
		{
			return new SimpleDateFormat(dateFormat).format(javaDate);
		}
	}

	public static int getYear()
	{
		return getYear(new Date());
	}

	public static int getYear(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getYear(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getYear(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.YEAR);
	}

	public static int getMonth()
	{
		return getMonth(new Date());
	}

	public static int getMonth(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getMonth(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getMonth(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.MONTH) + 1;
	}

	public static int getDay()
	{
		return getDay(new Date());
	}

	public static int getDay(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getDay(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getDay(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.DATE);
	}

	public static int getHour()
	{
		return getHour(new Date());
	}

	public static int getHour(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getHour(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getHour(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.HOUR_OF_DAY);
	}

	public static int getMinute()
	{
		return getMinute(new Date());
	}

	public static int getMinute(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getMinute(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getMinute(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.MINUTE);
	}

	public static int getSecond()
	{
		return getSecond(new Date());
	}

	public static int getSecond(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getSecond(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getSecond(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.SECOND);
	}

	public static int getMilliseconds()
	{
		return getMilliseconds(new Date());
	}

	public static int getMilliseconds(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			return getMilliseconds(new Timestamp(d.getTime()));
		}
		return 0;
	}

	public static int getMilliseconds(Timestamp ts)
	{
		GregorianCalendar calendar = new GregorianCalendar();
		calendar.setTimeInMillis(ts.getTime());
		return calendar.get(Calendar.MILLISECOND);
	}

	public static int getWeek()
	{
		return getWeek(new Date());
	}

	public static int getWeek(Timestamp ts)
	{
		if (TopUtil.isValidValue(ts))
		{
			return getWeek(new Date(ts.getTime()));
		}
		return 0;
	}

	public static int getWeek(Date d)
	{
		if (TopUtil.isValidValue(d))
		{
			GregorianCalendar gc = new GregorianCalendar();
			gc.setTime(d);
			return gc.get(gc.DAY_OF_WEEK) - 1;
		}
		return 0;
	}

	public static boolean isWorkDate(Date dt)
	{
		int d = getWeek(dt);
		return d > 0 && d <= 5;
	}

	public static Date getFirstDayOfCurrentWeek()
	{
		return getFirstDayOfCurrentWeek(new Date());
	}

	public static Date getFirstDayOfCurrentWeek(Date dt)
	{
		return dateAdd(dt, -getWeek(dt));
	}

	public static boolean isFirstDayOfCurrentWeek(Date dt)
	{
		return YkzbDateTimeUtil.dateToString(dt, SDFyyyyMMdd).equals(YkzbDateTimeUtil.dateToString(getFirstDayOfCurrentWeek(), SDFyyyyMMdd));
	}

	public static Date getLastDayOfCurrentWeek()
	{
		return dateAdd(getFirstDayOfCurrentWeek(), 6);
	}

	public static Date getLastDayOfCurrentWeek(Date dt)
	{
		return dateAdd(getFirstDayOfCurrentWeek(dt), 6);
	}

	public static Date getFirstDayOfCurrentMonth()
	{
		return getFirstDayOfCurrentMonth(new Date());
	}

	public static Date getFirstDayOfCurrentMonth(Date dt)
	{
		try
		{
			return new SimpleDateFormat(SDFyyyyMMdd).parse(YkzbDateTimeUtil.getYear(dt) + "-" + YkzbDateTimeUtil.getMonth(dt) + "-01");
		} catch (ParseException ex)
		{
			ex.printStackTrace();
		}
		return null;
	}

	public static Date getLastDayOfCurrentMonth()
	{
		return getLastDayOfCurrentMonth(new Date());
	}

	public static Date getLastDayOfCurrentMonth(Date dt)
	{
		try
		{
			Date d = new SimpleDateFormat(SDFyyyyMMdd).parse(YkzbDateTimeUtil.getYear(dt) + "-" + (YkzbDateTimeUtil.getMonth(dt) + 1) + "-01");
			return dateAdd(d, -1);
		} catch (ParseException ex)
		{
			ex.printStackTrace();
		}
		return null;
	}

	public static Date getFirstDayOfCurrentYear(Date dt)
	{
		try
		{
			return new SimpleDateFormat(SDFyyyyMMdd).parse(YkzbDateTimeUtil.getYear(dt) + "-01-01");
		} catch (ParseException ex)
		{
			ex.printStackTrace();
		}
		return null;
	}

	public static Date getLastDayOfCurrentYear(Date dt)
	{
		try
		{
			Date d = new SimpleDateFormat(SDFyyyyMMdd).parse(YkzbDateTimeUtil.getYear(dt) + 1 + "-01-01");
			return dateAdd(d, -1);
		} catch (ParseException ex)
		{
			ex.printStackTrace();
		}
		return null;
	}

	public static int getDaysOfMonth(String yyyyMM)
	{
		Date fromDt = stringToDate(yyyyMM + "01", "yyyyMMdd");
		return dateDiff(fromDt, getLastDayOfCurrentMonth(fromDt));
	}

	public static int getAge(Date d)
	{
		if (d == null)
		{
			return 0;
		}
		String ds = dateToString(d, SDFyyyyMMdd);
		int age = YkzbDateTimeUtil.getYear() - Integer.parseInt(ds.substring(0, 4)) - 1;
		if (Integer.parseInt(ds.substring(5, 7)) < getMonth())
		{
			age = age + 1;
		} else
		{
			if (Integer.parseInt(ds.substring(8, 10)) <= getDay())
			{
				age = age + 1;
			}
		}
		return age;
	}

	public static Date ageToDate(int age)
	{
		if (age <= 0)
		{
			return null;
		}
		Calendar ca = Calendar.getInstance();
		ca.set(getYear() - age, getMonth() - 1, getDay());
		return ca.getTime();
	}

	public static String getYearMonth(Date start, Date end)
	{
		int days = YkzbDateTimeUtil.dateDiff(start, end);
		if (days > 360 && days < 367)
		{
			return "1年";
		}
		if (days < 360)
		{
			int n = days / 30;
			if (days % 30 > 10)
			{
				n++;
			}
			return n + "个月";
		} else
		{
			int yr = days / 365;
			days = days % 365;
			int mn = 0;
			if (days > 25 && days < 30)
			{
				mn = 1;
			} else
			{
				mn = days / 30;
				if (days % 30 > 10)
				{
					mn++;
				}
				if (mn == 12)
				{
					yr++;
					mn = 0;
				}
			}
			if (mn > 0)
			{
				return yr + "年" + mn + "个月";
			} else
			{
				return yr + "年";
			}
		}
	}

	public static String dateToString(Date date, String format)
	{
		if (date == null || format == null)
		{
			return null;
		}
		return new SimpleDateFormat(format).format(date);
	}

	public static Date stringToDate(String date, String format)
	{
		if (date == null || format == null || date == "")
		{
			return null;
		}
		try
		{
			return new SimpleDateFormat(format).parse(date);
		} catch (ParseException ex)
		{
			return null;
		}
	}

	public static String getBirthDayByIdCard(String idCard)
	{
		// 441622'19810911'4176
		// 440103'511217'271
		String bir = null;
		int len = idCard.length();
		if (len == 15)
		{
			bir = "19" + idCard.substring(6, 8) + "-" + idCard.substring(8, 10) + "-" + idCard.substring(10, 12);
		} else if (len == 18)
		{
			bir = idCard.substring(6, 10) + "-" + idCard.substring(10, 12) + "-" + idCard.substring(12, 14);
		}
		return bir;
	}

	public static String hmsDiff(Date first, Date second)
	{
		if (first == null || second == null)
		{
			return "";
		}
		String str = "";
		if (first.after(second))
		{
			str += "-";
		}
		long time = Math.abs(second.getTime() - first.getTime());
		long hours = 0, minutes = 0, seconds = 0;
		hours = time / YkzbDateTimeUtil.millisecondsPerHour;
		if (hours > 0)
		{
			time = time % YkzbDateTimeUtil.millisecondsPerHour;
		}
		minutes = time / YkzbDateTimeUtil.millisecondsPerMinute;
		if (minutes > 0)
		{
			seconds = time % YkzbDateTimeUtil.millisecondsPerMinute / 1000;
		} else
		{
			seconds = time / 1000;
		}
		return str + (hours > 9 ? hours : "0" + hours) + ":" + (minutes > 9 ? minutes : "0" + minutes) + ":" + (seconds > 9 ? seconds : "0" + seconds);
	}

	public static String dhmsDiff(Date first, Date second)
	{
		if (first == null || second == null)
		{
			return "";
		}
		String str = "";
		if (first.after(second))
		{
			str += "-";
		}
		long time = Math.abs(second.getTime() - first.getTime());
		long days = 0, hours = 0, minutes = 0, seconds = 0;
		days = time / (YkzbDateTimeUtil.millisecondsPerHour * 24);
		if (days > 0)
		{
			time = time % (YkzbDateTimeUtil.millisecondsPerHour * 24);
		}
		hours = time / YkzbDateTimeUtil.millisecondsPerHour;
		if (hours > 0)
		{
			time = time % YkzbDateTimeUtil.millisecondsPerHour;
		}
		minutes = time / YkzbDateTimeUtil.millisecondsPerMinute;
		if (minutes > 0)
		{
			seconds = time % YkzbDateTimeUtil.millisecondsPerMinute / 1000;
		} else
		{
			seconds = time / 1000;
		}
		return str + days + "," + (hours > 9 ? hours : "0" + hours) + ":" + (minutes > 9 ? minutes : "0" + minutes) + ":" + (seconds > 9 ? seconds : "0" + seconds);
	}

	public static Date genDate(String year, String month)
	{
		Calendar cal = Calendar.getInstance();
		cal.set(Integer.parseInt(year), Integer.parseInt(month) - 1, 0, 0, 0, 0);
		cal.set(Calendar.HOUR_OF_DAY, 24);
		return cal.getTime();
	}

	public static Date parseStandardDate(String value)
	{
		Date date = null;
		int n = value.length();
		try
		{
			if (n >= "yyyy-MM-dd HH:mm:ss.S".length())
			{
				date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S").parse(value);
			} else if (n == "yyyy-MM-dd HH:mm:ss".length())
			{
				date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value);
			} else if (n == "yyyy-MM-dd HH:mm".length())
			{
				date = new SimpleDateFormat("yyyy-MM-dd HH:mm").parse(value);
			} else if (n == "yyyy-MM-dd HH".length())
			{
				date = new SimpleDateFormat("yyyy-MM-dd HH").parse(value);
			} else if (n == "yyyy-MM-dd".length())
			{
				date = new SimpleDateFormat("yyyy-MM-dd").parse(value);
			} else if (n == "yyyy-MM".length())
			{
				date = new SimpleDateFormat("yyyy-MM").parse(value);
			}
		} catch (ParseException e)
		{
			Log log = LogFactory.getLog(YkzbDateTimeUtil.class.getName());
			log.warn("Can not parse [" + value + "] to java.util.Date");
		}
		return date;
	}

	public static Date toDateStart(Date date)
	{
		return stringToDate(dateToString(date, SDFyyyyMMdd), SDFyyyyMMdd);
	}

	public static Date toDateEnd(Date date)
	{
		return stringToDate(dateToString(date, SDFyyyyMMdd) + " 23:59:59", SDFyyyyMMddHHmmss);
	}

	public static void main(String[] args)
	{
		// System.out.println(YkzbDateTimeUtil.getWeek(YkzbDateTimeUtil.stringToDate("2014-09-14",
		// SDFyyyyMMdd)));
	}

	/***
	 * @Title: checkIfInNowTime
	 * @Description: 查看当前时间是否在两个参数时间之内
	 * @author JOANDORA
	 */
	public static boolean checkIfInNowTime(Date start, Date end)
	{
		start = toDateStart(start);
		end = toDateStart(end);
		if (null == start || null == end)
		{
			return false;
		}
		Date now = toDateStart(new Date());
		if (1 > start.compareTo(now) && -1 < end.compareTo(now))
		{
			return true;
		}
		return false;
	}

	/***
	 * @Title: checkIfAfterNowTime
	 * @Description: 检查所给时间是否在当前时间之后
	 * @author JOANDORA
	 */
	public static boolean checkIfAfterNowTime(Date time)
	{
		time = toDateStart(time);
		if (null == time)
		{
			return false;
		}
		Date now = toDateStart(new Date());
		if (1 == time.compareTo(now))
		{
			return true;
		}
		return false;
	}

	/**
	 * @Title: checkIfBeforeNowTime
	 * @Description: 检查所给时间是否在 当前时候之前
	 */
	public static boolean checkIfBeforeNowTime(Date time)
	{
		if (null == time)
		{
			return false;
		}
		time = toDateStart(time);
		Date now = toDateStart(new Date());
		if (-1 == time.compareTo(now))
		{
			return true;
		}
		return false;
	}
}
